From: Ivan Molodetskikh Date: Tue, 8 Feb 2022 16:18:01 +0000 (+0300) Subject: panel: Add a screen recording indicator X-Git-Tag: archive/raspbian/50.5-1+rpi1~1^2~530^2^2~38 X-Git-Url: https://dgit.raspbian.org/%22http://www.example.com/cgi/%22/%22http:/www.example.com/cgi/%22?a=commitdiff_plain;h=6ec84800524a431d70c7bb5901c2c70f78ebd539;p=gnome-shell.git panel: Add a screen recording indicator The indicator shows the recording duration and lets the user stop it on click. It is more discoverable than the stop entry in the aggregate menu. The class extends ButtonBox directly rather than Button because Button does nothing that it uses, and actually causes issues with its dummy menu (its vfunc_hide() throws an "open-state-changed: Error: incorrect pop"). The menu-set signal declaration is required by the panel. The screencast is stopped upon button press in vfunc_event(), which matches PanelMenu.Button's input handling. Part-of: --- diff --git a/data/theme/gnome-shell-sass/widgets/_panel.scss b/data/theme/gnome-shell-sass/widgets/_panel.scss index 7e577e828..feeb1a7a2 100644 --- a/data/theme/gnome-shell-sass/widgets/_panel.scss +++ b/data/theme/gnome-shell-sass/widgets/_panel.scss @@ -38,6 +38,18 @@ $panel_transition_duration: 250ms; // same as the overview transition duration } } + &.screen-recording-indicator { + box-shadow: inset 0 0 0 100px $screenshot_ui_button_red; + + StBoxLayout { + spacing: $base_spacing; + } + + StIcon { + icon-size: $base_icon_size; + } + } + &:active, &:overview, &:focus, &:checked { box-shadow: inset 0 0 0 100px transparentize($panel_fg_color, 0.8); @@ -50,6 +62,10 @@ $panel_transition_duration: 250ms; // same as the overview transition duration box-shadow: inset 0 0 0 100px transparentize($panel_fg_color, 0.8); } } + + &.screen-recording-indicator { + box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.15); + } } &:hover { @@ -60,6 +76,10 @@ $panel_transition_duration: 250ms; // same as the overview transition duration box-shadow: inset 0 0 0 100px transparentize($panel_fg_color, 0.85); } } + + &.screen-recording-indicator { + box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.1); + } } &:active:hover, &:overview:hover, &:focus:hover, &:checked:hover { @@ -70,6 +90,10 @@ $panel_transition_duration: 250ms; // same as the overview transition duration box-shadow: inset 0 0 0 100px transparentize($panel_fg_color, 0.75); } } + + &.screen-recording-indicator { + box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.2); + } } // status area icons @@ -109,6 +133,10 @@ $panel_transition_duration: 250ms; // same as the overview transition duration box-shadow: inset 0 0 0 100px rgba(255,255,255, 0.15); } } + + &.screen-recording-indicator { + box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.15); + } } &:hover { @@ -119,6 +147,10 @@ $panel_transition_duration: 250ms; // same as the overview transition duration box-shadow: inset 0 0 0 100px rgba(255,255,255, 0.10); } } + + &.screen-recording-indicator { + box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.1); + } } &:active:hover, &:overview:hover, &:focus:hover, &:checked:hover { @@ -129,6 +161,10 @@ $panel_transition_duration: 250ms; // same as the overview transition duration box-shadow: inset 0 0 0 100px rgba(255,255,255, 0.2); } } + + &.screen-recording-indicator { + box-shadow: inset 0 0 0 100px transparentize($screenshot_ui_button_red, 0.2); + } } } } diff --git a/js/ui/panel.js b/js/ui/panel.js index ea40998a5..78064f73f 100644 --- a/js/ui/panel.js +++ b/js/ui/panel.js @@ -468,6 +468,7 @@ const PANEL_ITEM_IMPLEMENTATIONS = { 'a11y': imports.ui.status.accessibility.ATIndicator, 'keyboard': imports.ui.status.keyboard.InputSourceIndicator, 'dwellClick': imports.ui.status.dwellClick.DwellClickIndicator, + 'screenRecording': imports.ui.status.remoteAccess.ScreenRecordingIndicator, }; var Panel = GObject.registerClass( diff --git a/js/ui/sessionMode.js b/js/ui/sessionMode.js index 92d91fc60..7d83ddb6b 100644 --- a/js/ui/sessionMode.js +++ b/js/ui/sessionMode.js @@ -91,7 +91,7 @@ const _modes = { panel: { left: ['activities', 'appMenu'], center: ['dateMenu'], - right: ['dwellClick', 'a11y', 'keyboard', 'aggregateMenu'], + right: ['screenRecording', 'dwellClick', 'a11y', 'keyboard', 'aggregateMenu'], }, }, }; diff --git a/js/ui/status/remoteAccess.js b/js/ui/status/remoteAccess.js index d6d500cae..a63b257c5 100644 --- a/js/ui/status/remoteAccess.js +++ b/js/ui/status/remoteAccess.js @@ -1,7 +1,7 @@ // -*- mode: js; js-indent-level: 4; indent-tabs-mode: nil -*- -/* exported RemoteAccessApplet */ +/* exported RemoteAccessApplet, ScreenRecordingIndicator */ -const { GObject, Meta } = imports.gi; +const { Atk, Clutter, GLib, GObject, Meta, St } = imports.gi; const Main = imports.ui.main; const PanelMenu = imports.ui.panelMenu; @@ -106,3 +106,73 @@ class RemoteAccessApplet extends PanelMenu.SystemIndicator { this._sync(); } }); + +var ScreenRecordingIndicator = GObject.registerClass({ + Signals: { 'menu-set': {} }, +}, class ScreenRecordingIndicator extends PanelMenu.ButtonBox { + _init() { + super._init({ + reactive: true, + can_focus: true, + track_hover: true, + accessible_name: _('Stop Screencast'), + accessible_role: Atk.Role.PUSH_BUTTON, + }); + this.add_style_class_name('screen-recording-indicator'); + + this._box = new St.BoxLayout(); + this.add_child(this._box); + + this._label = new St.Label({ + text: '0:00', + y_align: Clutter.ActorAlign.CENTER, + }); + this._box.add_child(this._label); + + this._icon = new St.Icon({ icon_name: 'stop-symbolic' }); + this._box.add_child(this._icon); + + this.hide(); + Main.screenshotUI.connect( + 'notify::screencast-in-progress', + this._onScreencastInProgressChanged.bind(this)); + } + + vfunc_event(event) { + if (event.type() === Clutter.EventType.TOUCH_BEGIN || + event.type() === Clutter.EventType.BUTTON_PRESS) + Main.screenshotUI.stopScreencast(); + + return Clutter.EVENT_PROPAGATE; + } + + _updateLabel() { + const minutes = this._secondsPassed / 60; + const seconds = this._secondsPassed % 60; + this._label.text = '%d:%02d'.format(minutes, seconds); + } + + _onScreencastInProgressChanged() { + if (Main.screenshotUI.screencast_in_progress) { + this.show(); + + this._secondsPassed = 0; + this._updateLabel(); + + this._timeoutId = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 1000, () => { + this._secondsPassed += 1; + this._updateLabel(); + return GLib.SOURCE_CONTINUE; + }); + GLib.Source.set_name_by_id( + this._timeoutId, '[gnome-shell] screen recording indicator tick'); + } else { + this.hide(); + + GLib.source_remove(this._timeoutId); + delete this._timeoutId; + + delete this._secondsPassed; + } + } +});